Payload-based permission filters applied at query time
The standard approach is to store the access control information on each chunk as a payload field (or fields) and to apply a filter at query time that restricts the search to the documents the user is permitted to view. The permission model typically has two parts: the user's identities (user ID, group memberships, roles) and the document's access rules (which identities or groups can view it). At query time, the application expands the user's identities into a list and constructs a filter that matches chunks whose permission field intersects that list. If the permission model is simple - a single tenant, a single role - the filter is a must on the tenant and a should over the roles. If it is more complex - hierarchical groups, nested permissions, document-specific grants - the application must resolve the user's effective permissions before constructing the filter. The filter is applied during the vector search, not after, so the search only returns chunks the user can see. This is essential: a post-filter would retrieve chunks the user cannot see and then discard them, which wastes work and can leak information through timing or result counts.
The mechanism is that Qdrant evaluates the filter for each candidate during the HNSW traversal, so a chunk that fails the permission check is never returned. The permission field must be indexed as a keyword field, and if permissions are a list, the keyword index supports membership tests. The application's job is to translate the user's identity into the filter. For a simple role-based model, the filter is a should over the user's roles, which matches any chunk whose allowed_roles contains at least one of them. For a group-based model, the application resolves the user's group memberships (including nested groups if necessary) and constructs a should over those groups. For a document-level grant model, the application may need to consult an external permission store to determine which documents the user can view, and then either construct a filter over document IDs (which can be large) or use a precomputed permission token that is stored on the chunk. The choice depends on the size and complexity of the permission model: simple role-based models fit entirely in the payload, while complex models require an external store and a tokenization scheme. The critical property is that the filter must be applied at query time by a trusted service that knows the user's identity - clients must not be able to bypass it.
Store permissions on each chunk: allowed_roles, allowed_groups, tenant_id, or a permission token.
Index the permission fields: keyword index for role/group arrays, is_tenant for tenant.
Expand user identities at query time: resolve roles, groups, and effective permissions.
Construct a filter: must on tenant, should over roles/groups, must_not on explicit denials.
Apply the filter during retrieval, not after - post-filtering wastes work and can leak.
Trusted service: the query must be issued by a service that knows the user's identity, never by the client directly.
Precomputed tokens: for complex permission models, store a token on the chunk and match against the user's tokens.
Deny by default: if the filter does not match, the chunk is not returned.
The trade-off is between permission model complexity and query performance. Simple role-based permissions fit entirely in the payload and the filter is cheap. Complex models with hierarchical groups, document-level grants, or deny rules require either a large filter (which is slow) or a precomputed token (which requires an external system to mint tokens and a process to keep them in sync). The common mistake is to apply the permission filter after the vector search, which is both wasteful and can leak information. The second mistake is to trust the client to construct the filter, which means a malicious client can omit it and retrieve anything. The third mistake is to use a permission model that requires a filter over thousands of document IDs, which is slow and does not scale. The fourth mistake is to forget the deny case - a user may be in a group that grants access but also in a group that denies it, and the filter must handle both. Version note: Qdrant's filter semantics and the available payload index types have evolved, but the fundamental pattern of storing permissions in the payload and filtering at query time has been stable. The JWT RBAC payload filter capability, which might have enforced permissions at the database layer, was deprecated in 1.15 and removed in 1.16 - the trusted-service pattern is now the only safe approach for document-level permissions.
Version-dependent: the JWT RBAC payload filter capability was deprecated in Qdrant 1.15 and removed in 1.16. This means the database cannot enforce document-level permissions on its own; the trusted-service pattern is the correct approach for current versions. The payload index types and filter semantics have evolved, but the fundamental pattern of storing permissions in the payload and filtering at query time has been stable. For collection-level scoping, JWT RBAC is still available (1.9+) and can restrict a token to specific collections, which is a useful complement to the per-chunk permission filter.
You store documents with no permission metadata and now need to restrict access. Describe the schema change and the re-ingestion.
A teammate filters permissions after the vector search. Explain why that is wrong and how to fix it.
Your permission model has roles and groups. Describe the filter you would construct and how you would test that it does not leak data.
A user reports seeing a document they should not have access to. Describe how you would investigate and fix the issue.
Design the access control for a RAG system serving a law firm with client-matter-document hierarchies. Specify the payload schema, the filter construction, and the trusted-service architecture.
You need to support permission changes (grants and revocations) without re-ingesting all chunks. Describe the architecture that achieves this.
You are designing a multi-tenant RAG system where each tenant has its own permission model and some tenants have strict isolation requirements. Describe the architecture, the isolation guarantees, and the failure modes.
A compliance auditor asks you to prove that no user can retrieve a chunk they are not permitted to view. Describe the evidence and the testing you would provide.